if GetModConfigData("sw_equipcontrol") then return end

local thread
local thread_id = "shroomcake_fight"
local cutil = require "libs/calcutil"
local tutil = require "libs/tableutil"
local TheInput = GLOBAL.TheInput
local SRPC = GLOBAL.SendRPCToServer
local RPC = GLOBAL.RPC
local ACT = GLOBAL.ACTIONS
local Sleep = GLOBAL.Sleep
local FRAMES = GLOBAL.FRAMES
local function mySleep(num)
    if type(num) ~= "number" or num < 0 then
        TIP("站撸模式", "red", "帧数超出阈值！", "head")
        num = 0
    end
    Sleep(num*FRAMES)
end

local function stop(tips)
    GLOBAL.KillThreadsWithID(thread_id)
    thread = nil
end

local state = "mode0"
local states = {
    mode0 = "关闭",
    mode1 = "优先切撸 - 边走边撸【推荐】",
    mode2 = "优先切撸 - 原地站撸【不推荐】",
    mode3 = "禁止切撸 - 边走边撸",
    mode4 = "禁止切撸 - 原地站撸【不推荐】",
}

local function WalkToPoint(w_pos, inst)
    local act = GLOBAL.BufferedAction(inst, nil, ACT.WALKTO, nil, w_pos)
    act.preview_cb = function()
        SRPC(RPC.LeftClick, ACT.WALKTO.code, w_pos.x, w_pos.z)
    end
    local c = inst.components and inst.components.playercontroller
    if c and c.locomotor then
        c:DoAction(act)
    else
        act.preview_cb()
    end
end
local function AttackTarget(inst, target, t_pos, controller)
    local act = GLOBAL.BufferedAction(inst, target, ACT.ATTACK, nil, t_pos, nil, nil, true, nil)
    SRPC(RPC.AttackButton, target, true, true)
    if controller and controller.locomotor then
        controller:DoAction(act)
        return true
    end
end
local attackdelay, walkdelay = 0, 0
local function fn(target, inst, controller)
    if not thread then
        thread = GLOBAL.StartThread(function()
            while thread and target and target:IsValid() do
                local w_range = inst and inst.replica and inst.replica.combat and inst.replica.combat:GetAttackRangeWithWeapon()
                local p_pos = inst:GetPosition()
                local t_pos = target:GetPosition()
                if type(w_range) == "number" then
                    local ad_delay = 0
                    local range = w_range + target:GetPhysicsRadius(0)
                    local w_pos = cutil:GetIntersectPotRadiusPot(t_pos, range-0.13, p_pos)
                    local distance = GetDist(p_pos.x,p_pos.z,t_pos.x,t_pos.z)
                    if distance > range then
                        WalkToPoint(w_pos, inst)
                        mySleep(2)
                    else
                        local mv = AttackTarget(inst, target, t_pos, controller)
                        if w_range == 4 then
                            if mv then
                                ad_delay = 0
                            else
                                ad_delay = 2
                            end
                        else
                            ad_delay = 0
                        end
                        local function runA()
                            if table.contains({"mode1", "mode3"} ,state) then
                                if mv then
                                    mySleep(10.1+ad_delay+attackdelay)
                                else
                                    mySleep(9.1+ad_delay+attackdelay)
                                end
                                SRPC(RPC.DirectWalking, cutil:GetDirection(p_pos, target:GetPosition(),"up"))
                                mySleep(0)
                                SRPC(RPC.StopWalking)
                            elseif table.contains({"mode2", "mode4"}, state) then
                                if mv then
                                    mySleep(11.1+ad_delay+attackdelay)
                                else
                                    mySleep(10.1+ad_delay+attackdelay)
                                end
                                SRPC(RPC.PredictWalking, p_pos.x,p_pos.z, true, false, nil, false)
                            else
                                TIP("站撸模式", "red", "请重新点击开关", "head")
                            end
                            mySleep(1+walkdelay)
                        end
                        if table.contains({"mode3", "mode4"}, state) then
                            runA()
                        else
                            local eq = GetItemFromAll(nil, nil, function(ent)
                                local slot = ent.replica and ent.replica.equippable and not ent.replica.equippable:IsEquipped() and ent.replica.equippable:EquipSlot()
                                if slot and slot~=GLOBAL.EQUIPSLOTS.HANDS then
                                    local eq_ing = GetEquippedItemFrom(slot)
                                    if eq_ing and eq_ing~=ent then
                                        return true
                                    end
                                end
                            end)
                            if eq and eq:IsValid() then
                                mySleep(4.1+ad_delay+attackdelay)
                                SRPC(RPC.UseItemFromInvTile, ACT.EQUIP.code, eq)
                                -- SendActionAndFn(GLOBAL.BufferedAction(inst, nil, ACT.EQUIP, eq_n), function()
                                --     SRPC(RPC.ControllerUseItemOnSelfFromInvTile, ACT.EQUIP.code, eq_n)
                                -- end)
                                mySleep(walkdelay)
                            else
                                runA()
                            end
                        end
                    end
                end
                if target and target:IsValid() and GetAnim(target)=="death" then
                    target = controller:GetAttackTarget(TheInput:IsControlPressed(GLOBAL.CONTROL_FORCE_ATTACK), nil, true)
                end
            end
            SRPC(RPC.StopWalking)
            stop()
        end, thread_id)
    end
end


local datatemp = require "libs/datatemp"
AddComponentPostInit("playercontroller", function(self, inst)
    if inst ~= GLOBAL.ThePlayer then return end
    local _OnControl = self.OnControl
    local function IsPressMoving()
        for _, state in pairs(datatemp:GetBtnTable())do
            if state then
                return state
            end
        end
    end
    
    self.OnControl = function(self, control, down, ...)
        local controls_move = datatemp:GetBtnTable()
        if not self.ismastersim and state~="mode0" and InGame() then
            if control == GLOBAL.CONTROL_ATTACK then
                if down and not IsPressMoving() then
                    local force_attack = TheInput:IsControlPressed(GLOBAL.CONTROL_FORCE_ATTACK)
                    local target = self:GetAttackTarget(force_attack, nil, true)
                    if target and target:IsValid() and not target:HasTag("butterfly")
                    then
                        return fn(target, inst, self)
                    end
                else
                    stop()
                end
            elseif table.containskey(controls_move, control) then
                controls_move[control] = down
                if down then
                    stop()
                end
            end
        end
        return _OnControl(self, control, down, ...)
    end
end)

local ID = "huxi_run_A"
local allow = false
local setting = require "libs/settingmanager"
local function save()
    setting:SaveSettingLine(ID, {
        attack = attackdelay,
        walk = 0,
        state = state,
        allow = allow,
    })
end

local function SW()
    if not allow then
        return TIP("站撸", "red", "该功能被禁用, 请在物品收藏页输入激活码...", "chat")
    end
    state = tutil:GetNextLoopKey(states, state)
    if state == "mode0" then
        stop()
    end
    TIP("站撸", "green", states[state], "chat")
    save()
end
if GetModConfigData("sw_A") == "biubiu" then
    DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("armor_ruins_leaf.tex"),
    "armor_ruins_leaf.tex", "站撸模式",
    "此功能请查看设置详情！",
    false, SW)
end
AddBindBtn("sw_A", SW)

local function printInfo()
    TIP("站撸模式", attackdelay==0 and walkdelay==0 and "blue" or "green", "攻击后摇:"..attackdelay.."帧，移动后摇："..walkdelay.."帧", "chat") 
    save()
end
local function setWalkDelay(n)
    if not allow or state == "mode0" or not InGame()  then
        return
    end
    if n < 0.01 and n > -0.01 then
        n = 0
    end
    walkdelay = n
    printInfo()
end
local function setAttackDelay(n)
    if not allow or state == "mode0" or not InGame() then
        return
    end
    if n < 0.01 and n > -0.01 then
        n = 0
    end
    attackdelay = n
    printInfo()
end
local _lock
AddPlayerActivatedFunc(function()
    if _lock then
        return
    end
    _lock = true
    local data = setting:GetSettingLine(ID)
    attackdelay = (data and type(data.attack) == "number" and data.attack) or 0
    walkdelay = (data and type(data.walk) == "number" and data.walk) or 0
    state = data and data.state or "mode0"
    allow = data and data.allow or false
end)
GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_UP, function() setAttackDelay(attackdelay+0.1) end)
GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_DOWN, function() setAttackDelay(attackdelay-0.1) end)
GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_LEFT, function()
    -- setAttackDelay(attackdelay-1) 
    setWalkDelay(walkdelay-0.1) 
end)
GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_RIGHT, function() 
    -- setAttackDelay(attackdelay+1) 
    setWalkDelay(walkdelay+0.1) 
end)

local PDS = require "screens/redux/popupdialog"
local T = require("screens/thankyoupopup")
AddClassPostConstruct("screens/redeemdialog", function(self)
    local _DoSubmitCode = self.DoSubmitCode
    local function gs(i)
        return self.entrybox.textboxes[i]:GetString()
    end
    self.DoSubmitCode = function(self, ...)
        if gs(1)..gs(2)..gs(3)..gs(4)..gs(5) == "01234567891011121314" then

            GLOBAL.TheFrontEnd:PushScreen(PDS("蘑菇慕斯 · 朝花夕拾󰀜", "你确定要启用站撸模式吗？这个功能可不推荐萌新使用。\n 用法：点击功能面板的站撸按钮或绑定的按键切换模式，攻击键会自动变站撸键。\n 当穿着的物品可以切A时会切A。 \n 上下左右方向键可调节攻击后摇和移动后摇。\n 该功能只能在启用洞穴且无【独行长路】模组的情况下使用。", {
                {
                    text = "好吧，下次一定！",
                    cb = function()
                        GLOBAL.TheFrontEnd:PopScreen()
                    end
                },
                {
                    text = "我知道了，启用！",
                    cb = function()
                        allow = true,
                        save()
                        GLOBAL.TheFrontEnd:PopScreen()
                        GLOBAL.TheFrontEnd:PushScreen(T({
                            {item = "无名氏", item_id = 0, gifttype = "CUPID"}
                        }))
                    end
                },
            }, nil, "big", "dark_wide") )
        end
        return _DoSubmitCode(self, ...)
    end
end)